use crate::json_basic::JsonNode;
use std::collections::HashMap;

/// 其他数据类型变json
pub trait FromAndToJson {
    fn from_json(json: &JsonNode) -> Self;
    fn to_json(&self) -> JsonNode;
}

impl FromAndToJson for String {
    fn from_json(json: &JsonNode) -> Self {
        match json {
            JsonNode::String(str) => str.clone(),
            _ => panic!("Cannot convert non-string type to string"),
        }
    }

    fn to_json(&self) -> JsonNode {
        JsonNode::String(self.clone())
    }
}

impl FromAndToJson for Vec<JsonNode> {
    fn from_json(json: &JsonNode) -> Self {
        match json {
            JsonNode::Array(arr) => arr.clone(),
            _ => panic!("Cannot convert non-string type to string"),
        }
    }

    fn to_json(&self) -> JsonNode {
        JsonNode::Array(self.clone())
    }
}

impl FromAndToJson for HashMap<String, JsonNode> {
    fn from_json(json: &JsonNode) -> Self {
        match json {
            JsonNode::Object(obj) => obj.clone(),
            _ => panic!("Cannot convert non-string type to string"),
        }
    }

    fn to_json(&self) -> JsonNode {
        JsonNode::Object(self.clone())
    }
}
impl FromAndToJson for bool {
    fn from_json(json: &JsonNode) -> Self {
        match json {
            JsonNode::Boolean(bool) => bool.clone(),
            _ => panic!("Cannot convert non-string type to string"),
        }
    }

    fn to_json(&self) -> JsonNode {
        JsonNode::Boolean(self.clone())
    }
}

// impl FromAndToJson for f64 {
//     fn from_json(json: &JsonNode) -> Self {
//         match json {
//             JsonNode::Number(num) => num.clone()
//             _ => panic!("Cannot convert non-string type to string"),
//         }
//     }
//
//     fn to_json(&self) -> JsonNode {
//         JsonNode::Number(self.clone())
//     }
// }

macro_rules! impl_from_and_to_json_for_number {
    ($($t:ty),*) => {
        $(
           impl FromAndToJson for $t {
                fn from_json(json: &JsonNode) -> Self {
                    match json {
                        JsonNode::Number(num) => num.clone() as $t,
                        _ => panic!("Cannot convert non-string type to string"),
                    }
                }

                fn to_json(&self) -> JsonNode {
                    JsonNode::Number(self.clone() as f64)
                }
           }
        )*
    };
}

impl_from_and_to_json_for_number!(
    i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64
);


#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::HashMap;

    #[test]
    fn test_string_conversion() {
        let json = JsonNode::String("Hello, World!".to_string());
        let string: String = String::from_json(&json);
        assert_eq!(string, "Hello, World!");

        let json_from_string = string.to_json();
        assert!(matches!(json_from_string, JsonNode::String(s) if s == "Hello, World!"));
    }

    #[test]
    #[should_panic(expected = "Cannot convert non-string type to string")]
    fn test_string_from_invalid_json() {
        let json = JsonNode::Number(42.0);
        let _string: String = String::from_json(&json);
    }

    #[test]
    fn test_vec_conversion() {
        let json = JsonNode::Array(vec![
            JsonNode::String("item1".to_string()),
            JsonNode::Number(42.0),
            JsonNode::Boolean(true),
        ]);

        let vec: Vec<JsonNode> = Vec::from_json(&json);
        assert_eq!(vec.len(), 3);

        let json_from_vec = vec.to_json();
        assert!(matches!(json_from_vec, JsonNode::Array(arr) if arr.len() == 3));
    }

    #[test]
    #[should_panic(expected = "Cannot convert non-string type to string")]
    fn test_vec_from_invalid_json() {
        let json = JsonNode::Object(HashMap::new());
        let _vec: Vec<JsonNode> = Vec::from_json(&json);
    }

    #[test]
    fn test_hashmap_conversion() {
        let mut map = HashMap::new();
        map.insert("key1".to_string(), JsonNode::String("value1".to_string()));
        map.insert("key2".to_string(), JsonNode::Number(42.0));

        let json = JsonNode::Object(map.clone());

        let hashmap: HashMap<String, JsonNode> = HashMap::from_json(&json);
        assert_eq!(hashmap.len(), 2);

        let json_from_hashmap = hashmap.to_json();
        assert!(matches!(json_from_hashmap, JsonNode::Object(obj) if obj.len() == 2));
    }

    #[test]
    #[should_panic(expected = "Cannot convert non-string type to string")]
    fn test_hashmap_from_invalid_json() {
        let json = JsonNode::Array(vec![]);
        let _hashmap: HashMap<String, JsonNode> = HashMap::from_json(&json);
    }

    #[test]
    fn test_bool_conversion() {
        let json = JsonNode::Boolean(true);
        let bool_value: bool = bool::from_json(&json);
        assert!(bool_value);

        let json_from_bool = bool_value.to_json();
        assert!(matches!(json_from_bool, JsonNode::Boolean(b) if b == true));
    }

    #[test]
    #[should_panic(expected = "Cannot convert non-string type to string")]
    fn test_bool_from_invalid_json() {
        let json = JsonNode::String("true".to_string());
        let _bool_value: bool = bool::from_json(&json);
    }

    #[test]
    fn test_number_conversion() {
        let json = JsonNode::Number(42.0);
        let num: i32 = i32::from_json(&json);
        assert_eq!(num, 42);

        let json_from_num = num.to_json();
        assert!(matches!(json_from_num, JsonNode::Number(n) if n == 42.0));
    }

    #[test]
    #[should_panic(expected = "Cannot convert non-string type to string")]
    fn test_number_from_invalid_json() {
        let json = JsonNode::String("42".to_string());
        let _num: i32 = i32::from_json(&json);
    }
}